package org.jsola.contract.common;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.timevale.esign.sdk.tech.bean.*;
import com.timevale.esign.sdk.tech.bean.result.AddAccountResult;
import com.timevale.esign.sdk.tech.bean.result.FileDigestSignResult;
import com.timevale.esign.sdk.tech.bean.result.GetAccountProfileResult;
import com.timevale.esign.sdk.tech.bean.result.Result;
import com.timevale.esign.sdk.tech.impl.constants.LicenseQueryType;
import com.timevale.esign.sdk.tech.impl.constants.SignType;
import com.timevale.esign.sdk.tech.service.AccountService;
import com.timevale.esign.sdk.tech.service.MobileService;
import com.timevale.esign.sdk.tech.service.UserSignService;
import com.timevale.esign.sdk.tech.v3.client.ServiceClient;
import lombok.extern.slf4j.Slf4j;
import org.jsola.contract.exception.ESignException;
import org.jsola.exception.ParamException;

import java.text.MessageFormat;

/**
 * 第三方签署
 * 接口文档：https://open.esign.cn/doc/detail?id=opendoc%2Fpaas_sdk%2Fwq86pt&namespace=opendoc%2Fpaas_sdk
 *
 * @author JanusMix
 */
@Slf4j
public class ESignHelper {

    private UserSignService userSignService;
    private MobileService mobileService;
    private AccountService accountService;

    public ESignHelper(ServiceClient serviceClient) {
        this.userSignService = serviceClient.userSignService();
        this.mobileService = serviceClient.mobileService();
        this.accountService = serviceClient.accountService();
    }

    /**
     * 签署账号生成服务
     * 创建个人账号
     *
     * @param personBean bean
     * @return 账户id
     */
    public String addPersonAccount(PersonBean personBean) {
        // 查询该证件号是否已注册过
        GetAccountProfileResult getAccountProfileResult = accountService.getAccountInfoByIdNo(personBean.getIdNo(), LicenseQueryType.MAINLAND);
        if (getAccountProfileResult != null && getAccountProfileResult.getErrCode() == 0) {
            return getAccountProfileResult.getAccountInfo().getAccountUid();
        }
        AddAccountResult acctRst = accountService.addAccount(personBean);
        if (acctRst.getErrCode() != 0) {
            log.error(MessageFormat.format("创建账号失败：errCode = {1},msg = {2}",
                    acctRst.getErrCode(), acctRst.getMsg()));
            throw new ParamException("认证信息有误，请核实后重新认证");
        } else {
            log.info("创建账号成功");
        }
        return acctRst.getAccountId();
    }

    /**
     * 签署账号生成服务
     * description 创建企业账户
     * <p>
     * 创建企业账户，所创建账户是半实名的，即在快捷签对接项目中可以正常签署，
     * 在e签宝平台中无法使用，必须重新通过实名认证后才可以正常使用
     * <p>
     * {@link AccountService#addAccount(OrganizeBean)}
     *
     * @param organizeBean {@link OrganizeBean}企业信息详情
     * @author 宫清
     * @since JDK1.7
     */
    public String addEnterpriseAccount(OrganizeBean organizeBean) {
        AddAccountResult acctRst = accountService.addAccount(organizeBean);
        if (acctRst.getErrCode() != 0) {
            // 抛出e签宝的错误信息   打印认证的参数
            log.error(MessageFormat.format("创建账号失败：errCode = {1},msg = {2}, 参数打印:{3}",
                    acctRst.getErrCode(), acctRst.getMsg()), JSON.toJSONString(organizeBean));
            throw new ParamException("认证信息有误，请核实后重新认证, 错误信息：" + acctRst.getErrCode());
        } else {
            log.info("创建账号成功");
        }
        return acctRst.getAccountId();
    }

    /**
     * 平台用户意愿签署认证服务
     * 发送签署验证短信，调用此接口后，签署时需要调用相应的短信验证签署接口。
     *
     * @param accountId 账户id
     */
    public void sendSignCode(String accountId) {
        Result result = mobileService.sendSignMobileCode(accountId);
        if (result.getErrCode() != 0) {
            log.error("签署短信验证码获取失败：" + JSONObject.toJSONString(result));
            throw new ESignException("签署短信验证码获取失败");
        } else {
            log.info("签署短信验证码发送成功");
        }
    }

    /**
     * 平台用户意愿签署认证服务
     * description 平台用户PDF文件签署（短信验证）
     * <p>
     * 用指定账户的证书对文档进行签署，此签署过程不将文档上传至e签宝平台，
     * 只传递文档摘要信息。签署过程需要校验用户短信验证码，验证码必须通过e签宝接口发送
     * <p>
     * {@link UserSignService#localSafeSignPDF(String, String,
     * com.timevale.esign.sdk.tech.bean.AbstractSignPdfBean, PosBean, SignType, String)}
     *
     * @param accountId {@link String} 签署者账号标识，以此获取账户的证书进行签署
     * @param sealData  {@link String} 印章图片Base64，若为空最终签署后将没有直观图片展现
     * @param fileBean  {@link SignPDFFileBean} 签署PDF文档信息
     * @param signPos   {@link PosBean} 签章位置信息
     * @param signType  {@link SignType} 签章类型
     * @param code      {@link String} 短信验证码，必须通过e签宝接口发送
     * @since JDK1.7
     */
    public FileDigestSignResult localSignPDF(String accountId, String sealData, SignPDFFileBean fileBean, PosBean signPos,
                                             SignType signType, String code) {
        FileDigestSignResult signRst = userSignService.
                localSafeSignPDF(accountId, sealData, fileBean, signPos, signType, code);
        castSignRst(signRst);
        return signRst;
    }

    /**
     * description
     * 平台用户PDF无意愿认证签署服务
     * 平台用户PDF文件流签署
     *
     *
     * <p>
     * 用指定账户的证书对文档进行签署，此签署过程不将文档上传至e签宝平台，只传递文档摘要信息
     * <p>
     * {@link UserSignService#localSignPDF(String, String,
     * com.timevale.esign.sdk.tech.bean.AbstractSignPdfBean, PosBean, SignType)}
     *
     * @param accountId {@link String} 签署者账号标识，以此获取账户的证书进行签署
     * @param sealData  {@link String} 印章图片Base64，若为空最终签署后将没有直观图片展示
     * @param stream    {@link SignPDFStreamBean} 签署PDF文档信息
     * @param sigPos    {@link PosBean} 签章位置信息
     * @param signType  {@link SignType} 签章类型
     * @return {@link FileDigestSignResult} 签署返回结果
     * @author 宫清
     * @since JDK1.7
     */
    public FileDigestSignResult localSignPDF(String accountId, String sealData, SignPDFStreamBean stream, PosBean sigPos,
                                             SignType signType) {

        FileDigestSignResult signRst = userSignService
                .localSignPDF(accountId, sealData, stream, sigPos, signType);
        castSignRst(signRst);
        return signRst;
    }

    /**
     * description 签署结果处理
     *
     * @param rst {@link Result} 签署后返回的结果超类
     * @since JDK1.7
     */
    private void castSignRst(FileDigestSignResult rst) {
        if (rst.getErrCode() != 0) {
            log.error("合同日志追踪===>接口调用方(平台方)签署失败: errCode = {},msg = {}", rst.getErrCode(), rst.getMsg());
            throw new ESignException("调用接口签署失败：" + rst.getMsg());
        }
        log.info("合同日志追踪===>调用e签宝成功，结果 SignServiceId:{}," +
                        "FilePath:{}," +
                        "DstFilePath:{},SignDetailUrl:{},MarkBit:{}",
                rst.getSignServiceId(),
                rst.getFilePath(),
                rst.getDstFilePath(),
                rst.getSignDetailUrl(), rst.getMarkBit());
    }

}
